
/**
 * AppleIIGo
 * V2D Disk Image class
 * (C) 2008 by Marc S. Ressl (mressl@umich.edu)
 * Released under the GPL
 */

#include <stdio.h>
#include <string.h>
#include "V2DDiskImage.h"
#include "FDIDiskImage.h"

bool V2DDiskImage::isDiskImageValid(UINT32 diskType, char * diskImagePath) {
	if (diskType != FLOPPYDISKTYPE_5_25)
		return false;
	
	FILE * diskImageFile;
	if (!(diskImageFile = fopen(diskImagePath, "rb")))
		return false;
	
	bool isError = !readV2dHeader(diskImageFile, 0);
	
	fclose(diskImageFile);
	
	return !isError;
}

V2DDiskImage::V2DDiskImage(char * diskImagePath) :
NibbleDiskImage(diskImagePath) {
	if (!isDiskImageOpened())
		return;
	
	if (!readDiskImage(true))
		return;
	
	if (!allocateDisk())
		return;
	
	if (!readDiskImage(false))
		return;
	
	setWriteProtected(isWriteProtected());
}

V2DDiskImage::~V2DDiskImage() {
	if (!isDiskImageOpened())
		return;
	
	if (!isModified())
		return;
	
	FDIDiskImage::writeDiskImage(this);
}	

bool V2DDiskImage::readV2dHeader(FILE * diskImageFile,
								 UINT32 * diskImageTrackNum) {
	V2dHeaderType v2dHeader;
	
	fseek(diskImageFile, 0, SEEK_END);
	UINT32 diskImageByteNum = ftell(diskImageFile);
	fseek(diskImageFile, 0, SEEK_SET);
	
	if (fread(&v2dHeader, V2D_HEADER_BYTENUM, 1, diskImageFile) != 1)
		return false;
	
	UINT32 byteNum = getBigEndianUINT32(&v2dHeader.byteNum) +
		V2D_CONTAINER_BYTENUM;
	UINT32 trackNum = getBigEndianUINT16(&v2dHeader.trackNum);
	
	if (byteNum > diskImageByteNum)
		return false;
	if (strncmp(v2dHeader.id, "D5NI", 4))
		return false;
	if (trackNum > DISK_5_25_TRACKNUM)
		return false;
	
	if (diskImageTrackNum)
		*diskImageTrackNum = trackNum;
	
	return true;
}

bool V2DDiskImage::readDiskImageTrack(UINT32 diskImageTrackIndex,
									  bool isSetTrackBitNum) {
	V2dTrackType v2dTrack;
	
	if (fread(&v2dTrack, V2D_TRACKHEADER_BYTENUM, 1, diskImageFile) != 1)
		return false;
	
	UINT32 v2dTrackIndex = getBigEndianUINT16(&v2dTrack.trackIndex);
	UINT32 v2dTrackByteNum = getBigEndianUINT16(&v2dTrack.trackByteNum);
	
	if (v2dTrackIndex >= DISK_5_25_TRACKNUM)
		return false;
	if (!v2dTrackByteNum)
		return false;
	
	UINT8 v2dTrackData[v2dTrackByteNum];
	if (fread(v2dTrackData, v2dTrackByteNum, 1, diskImageFile) != 1)
		return false;
	
	setTrackIndex(v2dTrackIndex);
	setHeadIndex(0);
	UINT32 bitNum = writeTrack(v2dTrackData,
							   v2dTrackByteNum,
							   isSetTrackBitNum);
	if (isSetTrackBitNum)
		setTrackBitNum(bitNum);
	
	return true;
}

bool V2DDiskImage::readDiskImage(bool isSetTrackBitNum) {
	UINT32 diskImageTrackNum;
	
	fseek(diskImageFile, 0, SEEK_SET);
	
	if (!readV2dHeader(diskImageFile, &diskImageTrackNum))
		return false;
	
	for (UINT32 index = 0; index < diskImageTrackNum; index++)
		if (!readDiskImageTrack(index, isSetTrackBitNum))
			return false;
	
	return true;
}
